import { useState, useEffect, useCallback } from 'react';

interface QueryOptions<T> {
  manual?: boolean;
  defaultData?: T;
  onSuccess?: (data: T) => void;
  onError?: (error: Error) => void;
  deps?: React.DependencyList;
}

interface QueryResult<T, P = any> {
  data: T | undefined;
  loading: boolean;
  error: Error | null;
  run: (params?: P) => Promise<T>;
  refresh: () => Promise<T>;
  cancel: () => void;
}

/**
 * 数据查询自定义Hook
 * @param requestFn 请求函数
 * @param options 选项
 * @returns 查询结果
 */
export function useQuery<T, P = any>(
  requestFn: (params?: P) => Promise<T>,
  options: QueryOptions<T> = {}
): QueryResult<T, P> {
  const {
    manual = false,
    defaultData,
    onSuccess,
    onError,
    deps = [],
  } = options;

  const [data, setData] = useState<T | undefined>(defaultData);
  const [loading, setLoading] = useState<boolean>(!manual);
  const [error, setError] = useState<Error | null>(null);
  const [params, setParams] = useState<P | undefined>(undefined);
  const [cancelled, setCancelled] = useState<boolean>(false);

  const run = useCallback(
    async (runParams?: P): Promise<T> => {
      setLoading(true);
      setError(null);
      setCancelled(false);
      setParams(runParams);

      try {
        const result = await requestFn(runParams);

        if (cancelled) {
          return Promise.reject(new Error('请求已取消'));
        }

        setData(result);
        onSuccess?.(result);
        return result;
      } catch (e) {
        if (cancelled) {
          return Promise.reject(new Error('请求已取消'));
        }

        const err = e instanceof Error ? e : new Error(String(e));
        setError(err);
        onError?.(err);
        return Promise.reject(err);
      } finally {
        if (!cancelled) {
          setLoading(false);
        }
      }
    },
    [requestFn, onSuccess, onError]
  );

  const refresh = useCallback((): Promise<T> => {
    return run(params);
  }, [run, params]);

  const cancel = useCallback(() => {
    setCancelled(true);
    setLoading(false);
  }, []);

  useEffect(() => {
    if (!manual) {
      run();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [manual, ...deps]);

  return { data, loading, error, run, refresh, cancel };
} 